class SnapshotManager {
  static getInstance() {
    if (!SnapshotManager.instance) {
      SnapshotManager.instance = new SnapshotManager()
    }
    return SnapshotManager.instance
  }
  constructor() {
    this.snapshotIndex = -1
    this.snapshots = []
    this.events = {}
    this.lastAddType = ''
  }

  back() {
    this.snapshotIndex--;
    this.emitt('back', { snapshots: this.snapshots, snapshotIndex: this.snapshotIndex })
    return this.snapshots[this.snapshotIndex]
  }

  forward() {
    this.snapshotIndex++;
    this.emitt('forward', { snapshots: this.snapshots, snapshotIndex: this.snapshotIndex })
    return this.snapshots[this.snapshotIndex]
  }

  add(type, content) {
    if (this.snapshotIndex !== -1 && this.snapshotIndex !== this.snapshots.length - 1) {
      this.snapshots.splice(this.snapshotIndex + 1)
    }
    this.snapshots.push({ type, content })
    this.snapshotIndex = this.snapshots.length - 1

    this.emitt('add', { snapshots: this.snapshots, snapshotIndex: this.snapshotIndex })
  }

  isFirst() {
    return this.snapshotIndex <= 0
  }

  isEnd() {
    return this.snapshots.length === 0 || this.snapshots.length === 1 || this.snapshotIndex === this.snapshots.length - 1
  }

  hasSnapshot() {
    return this.snapshots.length > 0
  }

  isOnEdit() {
    return this.snapshots.length > 1
  }

  hasSnapshotType(type) {
    return this.snapshots.length > 0 && this.snapshots.some(ss => ss.type === type)
  }

  getCurrentLength() {
    return this.snapshots[this.snapshotIndex].length
  }

  restoreAllSnapshots(handle) {
    const types = Array.from(new Set(this.snapshots.map(ss => ss.type)))
    const typesFirstSnapshots = types.map(t => (this.snapshots.find(ss => ss.type === t)))
    typesFirstSnapshots.forEach((snapshot) => {
      handle(snapshot)
    })
    this.clear()
  }

  clear() {
    this.snapshots = []
    this.snapshotIndex = -1
    this.emitt('clear', { snapshots: this.snapshots, snapshotIndex: this.snapshotIndex }, () => {
      this.events = {}
      console.log('snapshot.js -> clear -> events:', this.events)
    })
  }

  on(eventType, eventHandler) {
    if (!this.events[eventType]) {
      this.events[eventType] = []
    }
    this.events[eventType].push(eventHandler)
  }

  off(eventType, eventHandler) {
    if (!this.events[eventType]) {
      let index = this.events[eventType].findIndex(e === eventHandler)
      this.events[eventType].splice(index, 1)
    }
  }

  emitt(eventType, data, afterEvent = () => { }) {
    let typeListeners = this.events[eventType]
    if (typeListeners) {
      typeListeners.forEach(l => {
        afterEvent && afterEvent()
        l(data)
      })
    }
  }
}

const snapshotManager = SnapshotManager.getInstance()

module.exports = { snapshotManager }